#include <stdio.h>
#include <string.h>

#include <mysql.h>
#include <sys/time.h>
#include <sys/unistd.h>

#include "mysql-connect.h"
#include "mysql-connect-pool.h"
#include "mysql-connect-factory.h"

int test01() {
    // 1. 初始化连接环境
    MYSQL *mysql = mysql_init(NULL);
    if (mysql == NULL) {
        printf("mysql_init() error\n");
        return -1;
    }

    // 2. 连接数据库服务器
    char *ip = "127.0.0.1";
    char *user = "root";
    char *password = "123123";
    char *database = "blue";
    int port = 3306;

    mysql = mysql_real_connect(mysql, ip, user, password, database, port, NULL, 0);
    if (mysql == NULL) {
        printf("mysql_real_connect() error\n");
        return -1;
    }

    // 设置编码为utf8
    printf("mysql api使用的默认编码: %s\n", mysql_character_set_name(mysql));
    mysql_set_character_set(mysql, "utf8");
    printf("mysql api使用的修改之后的编码: %s\n", mysql_character_set_name(mysql));

    printf("恭喜, 连接数据库服务器成功了...\n");

    // 3. 执行一个sql语句
    // 查询scott数据库下的dept部门表
    const char *sql = "select * from student";
    // 执行这个sql语句
    int ret = mysql_query(mysql, sql);
    if (ret != 0) {
        printf("mysql_query() a失败了, 原因: %s\n", mysql_error(mysql));
        return -1;
    }

    // 4. 取出结果集
    MYSQL_RES *res = mysql_store_result(mysql);
    if (res == NULL) {
        printf("mysql_store_result() 失败了, 原因: %s\n", mysql_error(mysql));
        return -1;
    }

    // 5. 得到结果集中的列数
    int num = mysql_num_fields(res);

    // 6. 得到所有列的名字, 并且输出
    MYSQL_FIELD *fields = mysql_fetch_fields(res);
    for (int i = 0; i < num; ++i) {
        printf("%s\t\t", fields[i].name);
    }
    printf("\n");

    // 7. 遍历结果集中所有的行
    MYSQL_ROW row;
    while ((row = mysql_fetch_row(res)) != NULL) {
        // 将当前行中的每一列信息读出
        for (int i = 0; i < num; ++i) {
            printf("%s\t\t", row[i]);
        }
        printf("\n");
    }

    // 8. 释放资源 - 结果集
    mysql_free_result(res);

    // 9. 写数据库
    // 以下三条是一个完整的操作, 对应的是一个事务
    // 设置事务为手动提交
    mysql_autocommit(mysql, 0);
    int ret1 = mysql_query(mysql, "insert into student values(61, '海军', '圣地玛丽乔亚', null)");
    int ret2 = mysql_query(mysql, "insert into student values(62, '七武海', '世界各地', null)");
    int ret3 = mysql_query(mysql, "insert into student values(63, '四皇', '新世界', null)");
    printf("ret1 = %d, ret2 = %d, ret3 = %d\n", ret1, ret2, ret3);

    if (ret1 == 0 && ret2 == 0 && ret3 == 0) {
        mysql_commit(mysql); // 提交事务
    } else {
        mysql_rollback(mysql); // 事务回滚
    }

    // 释放数据库资源
    mysql_close(mysql);
}

void test02() {
    MysqlConnect *connect = createConnect("127.0.0.1", "root", "123123", "blue", 3306);

    query(connect, "select * from student");

    while (next(connect)) {
        for (int i = 0; i < 4; ++i) {
            printf("%s ", value(connect, i));
        }
        printf("\n");
    }
}

void test03() {
    MysqlConnectFactory *factory = createMysqlConnectFactory("127.0.0.1", "root", "123123", "blue", 3306);

    MysqlConnect *connect = createMysqlConnect(factory);

    query(connect, "select * from student");

    while (next(connect)) {
        for (int i = 0; i < 4; ++i) {
            printf("%s ", value(connect, i));
        }
        printf("\n");
    }
}

void test04() {
    MysqlConnectPool *pool = createMysqlConnectPool("127.0.0.1", "root", "123123", "blue", 3306, 5, 300, 10, 50);

    MysqlConnect *connect = getConnect(pool);

    for (int i = 0; i < 50; ++i) {
        getConnect(pool);
    }

    query(connect, "select * from student");

    while (next(connect)) {
        for (int i = 0; i < 4; ++i) {
            printf("%s ", value(connect, i));
        }
        printf("\n");
    }

    printf("\n");

    freeConnect(pool, connect);

    destroyMysqlConnectPool(pool);
}

void test05() {
    struct timeval start, end;
    gettimeofday(&start, NULL);

    for (int i = 0; i < 5000; ++i) {
        MysqlConnect *connect = createConnect("127.0.0.1", "root", "123123", "blue", 3306);

        char *sql = malloc(sizeof(char) * 1024);
        sprintf(sql, "insert into student values (%d, 'blue', '123123', 'null')", i);

        update(connect, sql);

        free(sql);
        destroyConnect(connect);
    }

    gettimeofday(&end, NULL);
    int use_time = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;

    printf("single thread not use mysql connect pool use time: %d\n", use_time);

    // single thread not use mysql connect pool use time: 13545119
}

void test06() {
    struct timeval start, end;
    gettimeofday(&start, NULL);

    MysqlConnectPool *pool = createMysqlConnectPool("127.0.0.1", "root", "123123", "blue", 3306, 5, 300, 10, 50);

    for (int i = 0; i < 5000; ++i) {
        MysqlConnect *connect = getConnect(pool);

        char *sql = malloc(sizeof(char) * 1024);
        sprintf(sql, "insert into student values (%d, 'blue', '123123', 'null')", i);

        update(connect, sql);

        free(sql);
        freeConnect(pool, connect);
    }

    gettimeofday(&end, NULL);
    int use_time = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;

    printf("single thread use mysql connect pool use time: %d\n", use_time);

    // multi thread use mysql connect pool use time: 5310452
}

void *callback1(void *args) {
     int count = *(int *)args;

    for (int i = 500 * count; i < 500 * count + 500; ++i) {
        MysqlConnect *connect = createConnect("127.0.0.1", "root", "123123", "blue", 3306);

        char *sql = malloc(sizeof(char) * 1024);
        sprintf(sql, "insert into student values (%d, 'blue', '123123', 'null')", i);

        update(connect, sql);

        free(sql);
        destroyConnect(connect);
    }

    return NULL;
}

void test07() {
    MysqlConnect *connect = createConnect("127.0.0.1", "root", "123123", "blue", 3306);

    struct timeval start, end;
    gettimeofday(&start, NULL);

    pthread_t pid_list[10];

    for (int i = 0; i < 10; ++i) {
        int *p = malloc(sizeof(int));
        *p = i;
        pthread_create(&pid_list[i], NULL, callback1, p);
    }

    for (int i = 0; i < 10; ++i) {
        pthread_join(pid_list[i], NULL);
    }

    gettimeofday(&end, NULL);
    int use_time = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;

    printf("multi thread not use mysql connect pool use time: %d\n", use_time);

    // multi thread not use mysql connect pool use time: 2844329
}

static MysqlConnectPool *pool;

void *callback2(void *args) {
    int count = *(int *)args;

    for (int i = 500 * count; i < 500 * count + 500; ++i) {
        MysqlConnect *connect  = getConnect(pool);

        char *sql = malloc(sizeof(char) * 1024);
        sprintf(sql, "insert into student values (%d, 'blue', '123123', 'null')", i);

        update(connect, sql);

        free(sql);
        freeConnect(pool, connect);
    }

    return NULL;
}

void test08() {
    struct timeval start, end;
    gettimeofday(&start, NULL);

    pthread_t pid_list[10];
    pool = createMysqlConnectPool("127.0.0.1", "root", "123123", "blue", 3306, 5, 300, 10, 50);

    for (int i = 0; i < 10; ++i) {
        int *p = malloc(sizeof(int));
        *p = i;
        pthread_create(&pid_list[i], NULL, callback2, p);
    }

    for (int i = 0; i < 10; ++i) {
        pthread_join(pid_list[i], NULL);
    }

    gettimeofday(&end, NULL);
    int use_time = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;

    printf("multi thread use mysql connect pool use time: %d\n", use_time);

    // multi thread use mysql connect pool use time: 1173953
}

int main() {
    test08();

    return 0;
}